#! /usr/bin/python2.4
# _*_ coding: utf-8 _*_
#Created: 	2010-09-14
#			sidkim
#
#Version: v.0.2
#
#UPDATE:
#	- v.0.1		:base
#	- v.0.2		:implement DB connection
'''
HowTO: 	myClass = C_SecurityCheck()
		myClass.CheckSystem()
		myClass.SaveToDb()
 
'''
##GLOBALS
#DB connection info
g_DbAddress 	= "10.1.1.100"
g_DbID			= "sidkim"		#the account which ONLY can execute SPs. not even SELECT or UPDATE.
g_DbPass		= "pysql"		
g_DbName		= "SecTest"

#kernel Parameter item. It is a list, so items can be added or deleted.
g_KernelParamList = [\
					"net.ipv4.icmp_echo_ignore_broadcasts",\
					"net.ipv4.conf.all.accept_source_route",\
					"net.ipv4.tcp_syncookies",\
					"net.ipv4.conf.all.accept_redirect",\
					"net.ipv4.icmp_ignore_bogus_error_responses",\
					"net.ipv4.conf.all.rp_filter",\
					"net.ipv4.conf.all.log_martians",\
					"THIS_might_NOT_EXIST."\
					]

##IMPORTS
import platform
import os
import re
import MySQLdb

#################Beginning of Check Class#################
class C_SecurityCheck:
	#Member
	m_listSystemInfo = [] 		#(0: ServerName, 1:Kernel Version) x 1
	m_listIPaddress = []		#(0: ip address, 2:netmask) x N
	m_listRoutingTable = []		#(0: Destination, 2:Gateway) x N
	m_listHostsFile = []		#(0: contents) x N
	m_listTcpListen = []		#(0: local port, 1:remote port, 2:service) x N
	m_listTcpEst = []			#(0: local port, 1:remote port, 2:service) x N
	m_listUdpOpen = []			#(0: local port, 1:service) x N
	m_listProcess = []			#(0: user ID, 1:Process Name) x N
	m_listServiceRun = []		#(0: Running Service Name) x N
	m_listServiceStop = []		#(0: Stop Service Name) x N
	m_listKernelParam = []		#(0: Parameter, 1:Value) x N
	m_listRpmList = []			#(0: RPM list) x N
	m_listBootLoader = []		#(0: Boot Loader) x N
	m_listSshRootLogin = []		#(0: Login Value) x 1
	m_listAccounts = []			#(0: Account list) x N
	m_listAccountPolicy = []	#(0: Account Policy) x N
	
	
	#__init__
	def __init__(self):
		pass
		#'init' does NOTHING.
	
	
	def CheckSystem(self):
		pass
		#Start to Check.
		self.GetSystemInfo()
		self.GetIpAddress()
		self.GetRoutingTable()
		self.GetHostsFile()
		self.GetOpenedPorts()
		self.GetProcess()
		self.GetServiceList()
		self.GetKernelParam()
		self.GetRpmList()
		self.GetBootLoader()
		self.GetSshRootLogin()
		self.GetAccountsList()
		self.GetAccountPolicy()
	

	def GetSystemInfo(self):
		print "Getting System Info..."
		listSystemInfo = [item for item in platform.uname()]
		self.m_listSystemInfo.append(listSystemInfo[1])
		self.m_listSystemInfo.append(listSystemInfo[2])
		#print self.m_listSystemInfo
		self.f_B_Success(self.m_listSystemInfo)


	def GetIpAddress(self):
		print "Getting IP Address..."
		
		temp = os.popen("ifconfig | grep 'inet addr'").read().replace("\n"," ").replace(":"," ")
		find = re.findall(r"(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})",temp)
	
		#remove loopback int.
		del find[0:2]
		
		for i in range(0, len(find)/3):
			self.m_listIPaddress.append(find[0])
			self.m_listIPaddress.append(find[2])
			del find[0:3]
		
		self.f_B_Success(self.m_listIPaddress)
	
	
	def GetRoutingTable(self):
		print "Getting Routing Table..."
		
		temp = os.popen("netstat -anr | grep '^[0-9].'").read().replace("\n"," ")
		find = re.findall(r"(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})",temp)
		
		for i in range(0, len(find)/3):
			self.m_listRoutingTable.append(find[0])
			self.m_listRoutingTable.append(find[1])
			del find[0:3]
			
		self.f_B_Success(self.m_listRoutingTable)
	
	
	def GetHostsFile(self):
		print "Getting Hosts File..."
		
		temp = os.popen("cat /etc/hosts | grep '^[1-9]'").read()
		tempString = self.f_S_RemoveSpaces(temp)

		self.m_listHostsFile = tempString.split("\n")

		self.f_B_Success(self.m_listHostsFile)
		
	
	def GetOpenedPorts(self):
		#TCP Listening Port list
		print "Getting Listening TCP Ports..."
		temp = self.f_S_RemoveSpaces(os.popen("netstat -anpt | grep LISTEN").read())
		templist = temp.split(" ")
		
		for i in range(0, len(templist)/7):
			self.m_listTcpListen.append(templist[3])
			self.m_listTcpListen.append(templist[4])
			self.m_listTcpListen.append(templist[6])
			
			for j in range(0,7):
				templist.remove(templist[0])

		#print self.m_listTcpListen
		self.f_B_Success(self.m_listTcpListen)
		
		#TCP Established Port list
		print "Getting ESTABLISHED TCP Ports..."
		temp = self.f_S_RemoveSpaces(os.popen("netstat -anpt | grep ESTABLISHED").read())
		templist = temp.split(" ")
		
		for i in range(0, len(templist)/7):
			self.m_listTcpEst.append(templist[3])
			self.m_listTcpEst.append(templist[4])
			self.m_listTcpEst.append(templist[6])
			
			for j in range(0,7):
				templist.remove(templist[0])

		#print self.m_listTcpEst
		self.f_B_Success(self.m_listTcpEst)		
		
		#UDP Established Port list
		print "Getting Listening UDP Ports..."
		temp = self.f_S_RemoveSpaces(os.popen("netstat -anpu | grep udp").read())
		templist = temp.split(" ")
		
		for i in range(0, len(templist)/6):
			self.m_listUdpOpen.append(templist[3])
			self.m_listUdpOpen.append(templist[5])
			#self.m_listUdpOpen.append(templist[6])
			
			for j in range(0,6):
				templist.remove(templist[0])
				
		#print self.m_listUdpOpen
		self.f_B_Success(self.m_listUdpOpen)	


	def GetProcess(self):
		print "Getting Process..."
		temp = self.f_S_RemoveSpaces(os.popen("ps aux | grep '^[^USER]\w'").read())
		templist = re.sub(r"\s+\d+.+:\d+\s+", "\t", temp).replace("\t","%%").split("\n")
		
		for item in templist:
			tempitem = item.split("%%")
			if len(tempitem) == 2:
				self.m_listProcess.append(tempitem[0])
				self.m_listProcess.append(tempitem[1])
		#print self.m_listProcess
		self.f_B_Success(self.m_listProcess)
	
	
	def GetServiceList(self):
		#Running Service List
		print "Getting Running Service List..."
		command = "chkconfig --list | grep 3:on"
		temp = self.f_S_GetShellResult(command)
		templist = re.sub(r"\s+\d:\w{1,3}", "", temp).replace("\n"," ").split(" ")
		
		for item in templist:
			if not item == '':
				self.m_listServiceRun.append(item)
		pass
		self.f_B_Success(self.m_listServiceRun)
		
		#Stop Service List
		print "Getting Running Service List..."
		command = "chkconfig --list | grep 3:off"
		temp = self.f_S_GetShellResult(command)
		templist = re.sub(r"\s+\d:\w{1,3}", "", temp).replace("\n"," ").split(" ")
		
		for item in templist:
			if not item == '':
				self.m_listServiceStop.append(item)
		pass
		self.f_B_Success(self.m_listServiceStop)
				

	def GetKernelParam(self):
		global g_KernelParamItem
		print "Getting Kernel List..."
		command = "/sbin/sysctl -a | grep "
		
		for param in g_KernelParamList:
			temp = self.f_S_GetShellResult(command+param)
			
			if not temp == '':
				templist = temp.replace("\n","").split(" = ")
				self.m_listKernelParam.append(param)
				self.m_listKernelParam.append(templist[1])
			else:
				self.m_listKernelParam.append(param)
				self.m_listKernelParam.append("none")
		
		pass
		#print self.m_listKernelParam
		self.f_B_Success(self.m_listKernelParam)

	
	def GetRpmList(self):
		print "Getting RPM List..."
		command = "rpm -qa | sort"
		temp = self.f_S_GetShellResult(command)
		self.m_listRpmList = temp.split("\n")
		self.f_B_Success(self.m_listRpmList)
		#print self.m_listRpmList


	def GetBootLoader(self):
		print "Getting Boot Loader..."

		filename = "/boot/grub/grub.conf"
		command = "cat /boot/grub/grub.conf | grep '^[^#.+]'"
		splitText = " "
		###########################need to be fixed.!!
		self.m_listBootLoader = self.f_L_FindSomeCharInFile(filename, command, splitText)

		#print self.m_listBootLoader	
		self.f_B_Success(self.m_listBootLoader)


	def GetSshRootLogin(self):
		print "Getting SSH Config..."

		filename = "/etc/ssh/sshd_config"
		command = "cat /etc/ssh/sshd_config | grep '^PermitRootLogin [yes|no]'"
		splitText = " "
		
		self.m_listSshRootLogin = self.f_L_FindSomeCharInFile(filename, command, splitText)
		self.f_B_Success(self.m_listSshRootLogin)
		
	def GetAccountsList(self):
		print "Getting Accounts List..."
		
		filename = "/etc/passwd"
		command = "cat /etc/passwd"
		splitText = "\n"
		removedText = r":.+\d:\w{0,}:"
		
		if os.path.exists(filename):
			temp = self.f_S_GetShellResult(command)
			
			if not temp == "":
				temp2 = re.sub(removedText, ":", temp)
				result = temp2.replace(":",",").split(splitText)
				self.m_listAccounts = result
			else:
				pass
				self.m_listAccounts.append("can't get Info...")
		else:
			pass
		
		self.f_B_Success(self.m_listAccounts)
		#self.m_listAccounts.append("file not found")
		#print self.m_listAccounts
	
	
	def GetAccountPolicy(self):
		print "Getting Accounts Policy..."
		
		filename = "/etc/login.defs"
		command = "cat /etc/login.defs | grep '^[^#]'"
		splitText = "\n"
		
		if os.path.exists(filename):
			temp = self.f_S_GetShellResult(command)
			
			if not temp == "":
				self.m_listAccountPolicy = temp.replace("\t", ":").replace(" ", ":").split(splitText)
			else:
				pass
				self.m_listAccountPolicy.append("can't get Info...")
		else:
			pass

		self.f_B_Success(self.m_listAccountPolicy)
		#self.m_listAccountPolicy.append("file not found")
		#print self.m_listAccountPolicy
	
	
	def SaveToDb(self):
		pass
		print "Saving to DB..."
		global g_DbAddress, g_DbName, g_DbID, g_DbPass
		
		####OPEN DB####
		try:
			conn = MySQLdb.connect(db=g_DbName, user=g_DbID, passwd=g_DbPass, host=g_DbAddress)
			
		except:
			print "DB connection Failed."
			return 0
		
		####Data fetch####
		
		#save host info
		cursor = conn.cursor()
		cursor.callproc('hostinfo',(self.m_listSystemInfo[0], self.m_listSystemInfo[1]))
		cursor.close()
		
		#get host id from host name
		cursor = conn.cursor()
		command = "call gethostid('"\
								+ self.m_listSystemInfo[0] \
								+ "');"
		cursor.execute(command)
		hostid = cursor.fetchone()
		#print hostid[0]
		cursor.close()
		
		#save ip address
		cursor = conn.cursor()
		for i in range(0,len(self.m_listIPaddress)/2):
			cursor.callproc('ip',(hostid[0], self.m_listIPaddress[0], self.m_listIPaddress[1]))
			del self.m_listIPaddress[0:2]
		cursor.close()
		
		#save routing table
		cursor = conn.cursor()
		for i in range(0,len(self.m_listRoutingTable)/2):
			cursor.callproc('routing',(hostid[0], self.m_listRoutingTable[0], self.m_listRoutingTable[1]))
			del self.m_listRoutingTable[0:2]
		cursor.close()

		#save hosts file
		cursor = conn.cursor()
		for i in range(0,len(self.m_listHostsFile)/2):
			cursor.callproc('hosts',(hostid[0], self.m_listHostsFile[0]))
			del self.m_listHostsFile[0:1]
		cursor.close()

		#save ports info - TCP LISTEN
		cursor = conn.cursor()
		for i in range(0,len(self.m_listTcpListen)/3):
			cursor.callproc('porttcplist',(hostid[0], self.m_listTcpListen[0],self.m_listTcpListen[1],self.m_listTcpListen[2]))
			del self.m_listTcpListen[0:3]
		cursor.close()
		
		#save ports info - TCP ESTABLISHED
		cursor = conn.cursor()
		for i in range(0,len(self.m_listTcpEst)/3):
			cursor.callproc('porttcpest',(hostid[0], self.m_listTcpEst[0],self.m_listTcpEst[1],self.m_listTcpEst[2]))
			del self.m_listTcpEst[0:3]
		cursor.close()
		
		#save ports info - UDP LISTEN
		cursor = conn.cursor()
		for i in range(0,len(self.m_listUdpOpen)/2):
			cursor.callproc('portudplist',(hostid[0], self.m_listUdpOpen[0],self.m_listUdpOpen[1]))
			del self.m_listUdpOpen[0:2]
		cursor.close()
		
		#save process
		cursor = conn.cursor()
		for i in range(0,len(self.m_listProcess)/2):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('process',(hostid[0], self.m_listProcess[0],self.m_listProcess[1]))
			del self.m_listProcess[0:2]
		cursor.close()		
		
		#save service - running
		cursor = conn.cursor()
		for i in range(0,len(self.m_listServiceRun)):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('servicerun',(hostid[0], self.m_listServiceRun[0]))
			del self.m_listServiceRun[0:1]
		cursor.close()
		
		#save service - stop
		cursor = conn.cursor()
		for i in range(0,len(self.m_listServiceStop)):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('servicestop',(hostid[0], self.m_listServiceStop[0]))
			del self.m_listServiceStop[0:1]
		cursor.close()
		
		#save service - stop
		cursor = conn.cursor()
		for i in range(0,len(self.m_listKernelParam)/2):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('kernelparam',(hostid[0], self.m_listKernelParam[0], self.m_listKernelParam[1]))
			del self.m_listKernelParam[0:2]
		cursor.close()
		
		#save installed rpm
		cursor = conn.cursor()
		for i in range(0,len(self.m_listRpmList)):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('installedrpm',(hostid[0], self.m_listRpmList[0]))
			del self.m_listRpmList[0:1]
		cursor.close()
		
		#save boot loader
		cursor = conn.cursor()
		for i in range(0,len(self.m_listBootLoader)):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('bootset',(hostid[0], self.m_listBootLoader[0]))
			del self.m_listBootLoader[0:1]
		cursor.close()
		
		#save ssh root login
		cursor = conn.cursor()
		for i in range(0,len(self.m_listSshRootLogin)/2):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('sshlogin',(hostid[0], self.m_listSshRootLogin[0], self.m_listSshRootLogin[1]))
			del self.m_listSshRootLogin[0:2]
		cursor.close()
		
		#save ssh root login
		cursor = conn.cursor()
		for i in range(0,len(self.m_listAccounts)):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('accounts',(hostid[0], self.m_listAccounts[0]))
			del self.m_listAccounts[0:1]
		cursor.close()
		
		#save ssh root login
		cursor = conn.cursor()
		for i in range(0,len(self.m_listAccountPolicy)):
			#print self.m_listProcess[0],self.m_listProcess[1]
			cursor.callproc('passwdpol',(hostid[0], self.m_listAccountPolicy[0]))
			del self.m_listAccountPolicy[0:1]
		cursor.close()

		####CLOSE DB####
		conn.close()
		print "Saving has finished. OK."
	
		
#################util function#################
	#find TEXTs in a file.
	def f_L_FindSomeCharInFile(self, a_fileName, a_command, a_splitText):
		result = []
		if os.path.exists(a_fileName):
			temp = self.f_S_GetShellResult(a_command)
			
			if not temp == "":
				result = temp.replace("\n","").split(a_splitText)
			else:
				result.append("Vaule not Found")
		else:
			result.appen("File not Found")
		return result

	#returns text from command line.
	def f_S_GetShellResult(self, a_data):
		result = self.f_S_RemoveSpaces(os.popen(a_data).read())
		return result
	
	#multi spaces remover.
	def f_S_RemoveSpaces(self, a_data):
		pass
		result = re.sub(r"\s{2,}"," ",a_data)
		return result
	
	#after a module gathers info, this function checks the result is ok.
	def f_B_Success(self, a_data):
		if len(a_data) > 1:
			print "....Done.\n"
			return True
		else:
			print "None or ERROR!"
			return False

	#proto type of data-mining function. almost useless.
	def f_L_Mining(self, a_popenResult):
		a = a_popenResult.read().replace('\n',' ').split(' ')
		result = []
		for item in a:
			if not item == '':
				result.append(item)
		pass
		return result

	#text finder using regex in a list.
	def f_L_FindinList(self, a_pattern, a_list):
		import re
		pa = re.compile(a_pattern)
		for i in range(0,len(a_list)):
			if pa.search(a_list[i]):
				result = a_list[i].split(' = ')
				break
		else:
			result = ['not found','null']
		return result
#################End of Check Class#################

		
def main():
	pass
	myClass = C_SecurityCheck()
	myClass.CheckSystem()
	myClass.SaveToDb()

##Starting Point	
if __name__ == "__main__":
	main()
